package com.jt.resource.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.access.AccessDeniedHandler;

import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Map;

/**
 * 资源服务器的配置，在这个对象中重点要实现：
 * 1)JWT令牌解析的配置(客户端带着令牌访问资源时，要对令牌进行解析)
 * 2)启动资源访问的授权配置(不是所有登陆用户可以访问所有资源)
 */
@Configuration
@EnableResourceServer //此注解会启动资源服务器的默认配置
@EnableGlobalMethodSecurity(prePostEnabled = true) //执行方法之前启动权限检查
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    @Autowired
    private TokenStore tokenStore;

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        //super.configure(resources);
        //定义令牌生成策略，这里不是要创建令牌，是要解析令牌
        resources.tokenStore(tokenStore);
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        //super.configure(http);
        //1.关闭跨域攻击
        http.csrf().disable();
        //2.放行所有资源的访问(对资源的访问不做认证)
        http.authorizeRequests().anyRequest().permitAll();
        //如下写法为对/resource/**资源的访问必须认证以后才可以访问
        //http.authorizeRequests().mvcMatchers("/resource/**")
        //        .authenticated(); //假如没有认证就访问会报401异常

        //3.处理异常(授权异常)
//        http.exceptionHandling()
//                .authenticationEntryPoint(authenticationEntryPoint())/*未授权*/
//                .accessDeniedHandler(accessDeniedHandler())/*未认证*/
//        ;
    }



    @Bean/*无权限处理*/
    public AccessDeniedHandler accessDeniedHandler(){
//        return new AccessDeniedHandler() {
//            @Override
//            public void handle(HttpServletRequest httpServletRequest,
//                               HttpServletResponse httpServletResponse,
//                               AccessDeniedException e)
//                               throws IOException, ServletException {
//            }
//        };
        return (request,response, exception)->{
            //1.构建响应数据
            Map<String,Object> map=new HashMap<>();
            map.put("state", HttpServletResponse.SC_FORBIDDEN);//403
            map.put("message", "您没有这个资源的访问权限");
            //2.将响应数据写到客户端
            //2.1设置响应数据编码
            response.setCharacterEncoding("utf-8");
            //2.2告诉客户端要响应的数据类型，以及什么编码进行数据呈现
            response.setContentType("application/json;charset=utf-8");
            //2.3将数据转换为json
            String jsonStr=new ObjectMapper().writeValueAsString(map);
            //2.4将json写到客户端
            PrintWriter writer = response.getWriter();
            writer.println(jsonStr);
            writer.flush();
        };
    }

    @Bean/*未登录处理*/
    public AuthenticationEntryPoint authenticationEntryPoint() {
        return (request,response, exception)->{
            //1.构建响应数据
            Map<String,Object> map=new HashMap<>();
            map.put("state", HttpServletResponse.SC_UNAUTHORIZED);//401
            map.put("message", "您还没有登陆!");
            //2.将响应数据写到客户端
            //2.1设置响应数据编码
            response.setCharacterEncoding("utf-8");
            //2.2告诉客户端要响应的数据类型，以及什么编码进行数据呈现
            response.setContentType("application/json;charset=utf-8");
            //2.3将数据转换为json
            String jsonStr=new ObjectMapper().writeValueAsString(map);
            //2.4将json写到客户端
            PrintWriter writer = response.getWriter();
            writer.println(jsonStr);
            writer.flush();
        };
    }
}
